package com.rt.schedulenew.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ewell.sdk.business.EwellServiceTool;
import com.ewell.sdk.domain.MessageEntity;
import com.ewell.sdk.exception.SDKException;
import com.rt.schedulebase.core.config.MQConfig;
import com.rt.schedulebase.core.config.XRayMQConfig;
import com.rt.schedulebase.dto.ExamScheduleItemVo;
import com.rt.schedulebase.dto.esb.AccessControl;
import com.rt.schedulebase.dto.esb.MessageHeader;
import com.rt.schedulebase.dto.esb.schedule.response.xray.XRayResponseMsgDetail;
import com.rt.schedulebase.dto.esb.schedule.response.xray.XRayScheduleResponseESBEntry;
import com.rt.schedulebase.dto.esb.schedule.response.xray.XRayScheduleResponseMsg;
import com.rt.schedulebase.dto.esb.schedule.resquest.xray.XRayScheduleSendESBEntry;
import com.rt.schedulebase.dto.esb.schedule.resquest.xray.XRaySendMsg;
import com.rt.schedulebase.dto.esb.schedule.resquest.xray.XRaySendMsgInfo;
import com.rt.schedulebase.entity.*;
import com.rt.schedulebase.mapper.*;
import com.rt.schedulenew.api.XRayService;
import com.rt.schedulenew.utils.util.DateUtil;
import com.rt.schedulenew.utils.util.JacksonUtil;
import com.rt.schedulenew.utils.util.JsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.rt.schedulebase.dto.esb.schedule.resquest.ps35013.*;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ljy aka ryan
 * @date 2023/5/10$ 10:21$
 * @description 推送放射科逻辑
 */
@Service
public class XRayServiceImpl implements XRayService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private XRayMQConfig xRayMQConfig;

    @Autowired
    private DictExamItemMapper dictExamItemMapper;

    @Autowired
    private DictExamQueueMapper examQueueMapper;

    @Autowired
    private ExamScheduleItemMapper scheduleItemMapper;

    @Autowired
    private ExamApplyMapper examApplyMapper;

    @Autowired
    private ExamApplyItemMapper examApplyItemMapper;

    @Resource
    MQConfig mqConfig;

    private EwellServiceTool ewellServiceTool;

    @Override
    public List<DictExamItem> getPacsItemsByApplyNos(String mergeNo) {
        Map<String, List<String>> applyNos = new HashMap<>();
        List<String> applyNoList = new ArrayList<>();
        // 根据申请单号和序号获取检查项目编码
        String[] applyNoAndItemNos = mergeNo.split(",");
        for (String no : applyNoAndItemNos) {
            String[] split = no.split("-");
            String key = split[0];
            String itemNo = split[1];
            List<String> itemNos = new ArrayList<>();
            if (applyNos.containsKey(key)) {
                itemNos = applyNos.get(key);
            }
            itemNos.add(itemNo);
            applyNos.put(key, itemNos);
            applyNoList.add(key);
        }
        List<ExamApplyItem> examApplyItems = new ArrayList<>();
        for (String key : applyNos.keySet()) {
            List<String> itemNos = applyNos.get(key);
            QueryWrapper<ExamApplyItem> itemCodeQuery = new QueryWrapper<>();
            itemCodeQuery.eq("APPLY_NO", key);
            itemCodeQuery.in("ITEM_NO", itemNos);
            List<ExamApplyItem> applyItems = examApplyItemMapper.selectList(itemCodeQuery);
            examApplyItems.addAll(applyItems);
        }
        List<String> itemCodes = examApplyItems.stream().map(x -> x.getItemCode()).collect(Collectors.toList());


        //List<String> examClassList = Arrays.asList(xRayMQConfig.getExamClass().split(","));
        QueryWrapper<DictExamItem> itemQueryWrapper = new QueryWrapper<>();
        //itemQueryWrapper.in("EXAM_CLASS", examClassList);
        itemQueryWrapper.in("ITEM_CODE", itemCodes);
        return dictExamItemMapper.selectList(itemQueryWrapper);
    }

    /**
     * 发送
     */
    @Override
    public boolean sendXRayScheduleMsg(String mergeNo) {
        boolean result = true;
        // 未开启不推送
        if (!xRayMQConfig.getEnable() || StringUtils.isBlank(mergeNo)) {
            return result;
        }
//        Map<String, List<String>> applyNos = new HashMap<>();
        List<String> applyNoList = new ArrayList<>();
        // 根据申请单号和序号获取检查项目编码
        String[] applyNoAndItemNos = mergeNo.split(",");
        for (String no : applyNoAndItemNos) {
            String[] split = no.split("-");
            String key = split[0];
            applyNoList.add(key);
        }
//        // 根据申请单号和序号获取检查项目编码
//        String[] applyNoAndItemNos = mergeNo.split(",");
//        for (String no : applyNoAndItemNos) {
//            String[] split = no.split("-");
//            String key = split[0];
//            String itemNo = split[1];
//            List<String> itemNos = new ArrayList<>();
//            if (applyNos.containsKey(key)) {
//                itemNos = applyNos.get(key);
//            }
//            itemNos.add(itemNo);
//            applyNos.put(key, itemNos);
//            applyNoList.add(key);
//        }
//        List<ExamApplyItem> examApplyItems = new ArrayList<>();
//        for (String key : applyNos.keySet()) {
//            List<String> itemNos = applyNos.get(key);
//            QueryWrapper<ExamApplyItem> itemCodeQuery = new QueryWrapper<>();
//            itemCodeQuery.eq("APPLY_NO", key);
//            itemCodeQuery.in("ITEM_NO", itemNos);
//            List<ExamApplyItem> applyItems = examApplyItemMapper.selectList(itemCodeQuery);
//            examApplyItems.addAll(applyItems);
//        }
//        List<String> itemCodes = examApplyItems.stream().map(x -> x.getItemCode()).collect(Collectors.toList());
//
//        /**
//         *  1. 判断预约的项目是否放射科的检查
//         *  2. 构造发送消息内容
//         *  3. 发送并接收结果
//         *  4. 将需要的信息落库
//         */
//        List<String> examClassList = Arrays.asList(xRayMQConfig.getExamClass().split(","));
//        QueryWrapper<DictExamItem> itemQueryWrapper = new QueryWrapper<>();
//        itemQueryWrapper.in("EXAM_CLASS", examClassList);
//       itemQueryWrapper.in("ITEM_CODE", itemCodes);
        /**
         *  1. 判断预约的项目是否放射科的检查
         *  2. 构造发送消息内容
         *  3. 发送并接收结果
         *  4. 将需要的信息落库
         */
        List<DictExamItem> examItems = getPacsItemsByApplyNos(mergeNo);

        List<String> itemCodes = new ArrayList<>();
        if (!CollectionUtils.isEmpty(examItems)) {
            itemCodes = examItems.stream().map(x -> x.getItemCode()).collect(Collectors.toList());
            List<String> examClassList = Arrays.asList(xRayMQConfig.getExamClass().split(","));
            examItems = examItems.stream().filter(x -> examClassList.contains(x.getExamClass())).collect(Collectors.toList());
        }

        // 如果返回为空说明不是放射科的检查项目，直接返回
        if (CollectionUtils.isEmpty(examItems)) {
            logger.info("sendXRayScheduleMsg:没有获取到需要推送放射科的预约数据:{}", JsonUtil.toJson(itemCodes));
            return result;
        }


        // 获取预约信息
        ExamScheduleItemVo scheduleItemVo = scheduleItemMapper.queryScheduledDate(applyNoList.get(0));

        String dateTimeNow = DateUtil.date2Str(new Date(), DateUtil.FORMAT_DATETIME);
        // 构造发送的参数
        XRayScheduleSendESBEntry<XRaySendMsgInfo<XRayResponseMsgDetail>> sendESBEntry = new XRayScheduleSendESBEntry<>();
        MessageHeader header = new MessageHeader();

        header.setFid(xRayMQConfig.getPushPACSScheduleFid());
        header.setMsgDate(dateTimeNow);

        if (scheduleItemVo.getExamClass().contains("超声") || scheduleItemVo.getExamClass().contains("内镜")) {
            header.setTargetSysCode(xRayMQConfig.getPushCSTargetSysCode());
            header.setOrderNo(xRayMQConfig.getPushCSTargetScheduleOrderNo());
        } else {
            header.setTargetSysCode(xRayMQConfig.getPushPACSTargetSysCode());
            header.setOrderNo(xRayMQConfig.getPushPACSScheduleOrderNo());
        }
        header.setSourceSysCode(xRayMQConfig.getSourceSystemCode());
        header.setReturnFlag("0");
        header.setHospCode(xRayMQConfig.getHospCode());

        AccessControl accessControl = new AccessControl();
        accessControl.setFid(xRayMQConfig.getPushPACSScheduleFid());
        if (scheduleItemVo.getExamClass().contains("超声") || scheduleItemVo.getExamClass().contains("内镜")) {
            accessControl.setOrderNo(xRayMQConfig.getPushCSTargetScheduleOrderNo());
        } else {
            accessControl.setOrderNo(xRayMQConfig.getPushPACSScheduleOrderNo());
        }
        accessControl.setSysFlag("1");
        accessControl.setUserName(xRayMQConfig.getUserName());
        accessControl.setPassword(xRayMQConfig.getPassword());

        sendESBEntry.setAccessControl(accessControl);
        sendESBEntry.setMessageHeader(header);

        QueryWrapper<DictExamQueue> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("QUEUE_NAME", scheduleItemVo.getQueueName());
        DictExamQueue examQueue = examQueueMapper.selectOne(queryWrapper);
        if (Objects.isNull(examQueue)) {
            logger.error("没有找到队列名称为： " + scheduleItemVo.getQueueName() + "  的队列字典设置!");
            return result;
        }

        List<XRayResponseMsgDetail> details = new ArrayList<>();
        for (String x : applyNoList) {
            XRayResponseMsgDetail detail = new XRayResponseMsgDetail();
            detail.setEquisitionNo(x);
            details.add(detail);
        }

        XRaySendMsgInfo<XRayResponseMsgDetail> sendMsgInfo = new XRaySendMsgInfo<>();
        XRaySendMsg<XRayResponseMsgDetail> sendMsg = new XRaySendMsg<>();
        sendMsg.setId("1");
        sendMsg.setAction("insert");
        sendMsg.setLastUpdate(dateTimeNow);
        sendMsg.setDetail(details);
        sendMsg.setExamCategCode(examQueue.getDeviceType());
        sendMsg.setExamCategName(examQueue.getDeviceType());
        sendMsg.setRoomId(examQueue.getRoomId());
        // if (scheduleItemVo.getExamClass().contains("超声")) {
        //     sendMsg.setQueueId(ConsultingRoomChooseUtil.getUltrasonicRoom());
        // }
        String[] timeLists;
        if (StringUtils.isNoneBlank(scheduleItemVo.getScheduleApm())) {
            if (scheduleItemVo.getScheduleApm().contains("-")) {
                timeLists = scheduleItemVo.getScheduleApm().split("-");
            } else {
                timeLists = scheduleItemVo.getScheduleApm().split("~");
            }
        } else {
            timeLists = new String[2];
            timeLists[0] = "";
            timeLists[1] = "";
        }

        sendMsg.setReserveExamDate(scheduleItemVo.getScheduledDate() + " " + timeLists[0]);
        sendMsgInfo.setMsg(sendMsg);

        sendESBEntry.setMsgInfo(sendMsgInfo);
        String xml = JacksonUtil.toXmlString(sendESBEntry);

        logger.info("预约推送PACS-sendXRayScheduleMsg:{}", xml);

        String mqManager = xRayMQConfig.getPushPACSScheduleChangeMQ();
        if (scheduleItemVo.getExamClass().contains("超声") || scheduleItemVo.getExamClass().contains("内镜")) {
            mqManager = xRayMQConfig.getPushCSScheduleChangeMQ();
        }
        MessageEntity messageEntity = pushMsgWithResult2(mqManager, xRayMQConfig.getPushPACSScheduleChannelId(), xml);

        // 发送成功
        if (StringUtils.isNoneBlank(messageEntity.getMsg())) {
            XRayScheduleResponseESBEntry esbEntry =
                    JacksonUtil.readXmlValue(messageEntity.getMsg(), XRayScheduleResponseESBEntry.class);
            if (Objects.isNull(esbEntry) || Objects.isNull(esbEntry.getMsgInfo())) {
                logger.error("预约推送PACS失败内容为空!{}", esbEntry);
                result = false;
                return result;
            }
            /*
             * 1. 判断发送是否成功
             */
            XRayScheduleResponseMsg msg = esbEntry.getMsgInfo().getMsg();
            if ("0".equals(msg.getResultCode())) {
                result = false;
                return result;
            }
            // 申请单号
            List<String> applyNoLists = msg.getDetails().stream()
                    .map(XRayResponseMsgDetail::getEquisitionNo)
                    .filter(StringUtils::isNoneBlank).collect(Collectors.toList());

            // 更新 预约的影像号和排队号
            List<ExamScheduleItem> examScheduleItems = examApplyMapper.getExamScheduleItemByApplyNos(applyNoLists);
            for (ExamScheduleItem item : examScheduleItems) {
                item.setImageNo(msg.getImageNo());
                item.setPacsSortNo(msg.getNo());
                item.setPacsExamDept(msg.getTriageExamDept());
                logger.info("PACS返回影像号数据:{}", JacksonUtil.toJsonString(item));
                UpdateWrapper<ExamScheduleItem> updateWrapper = new UpdateWrapper<>();
                updateWrapper.set("IMAGE_NO", msg.getImageNo());
                updateWrapper.set("PACS_SORT_NO", msg.getNo());
                updateWrapper.set("PACS_EXAM_DEPT", msg.getTriageExamDept());
                updateWrapper.set("PLAN_EXAM_TIME", msg.getPlanExamTime());
                updateWrapper.eq("SCHEDULED_ID", item.getScheduledId());
                scheduleItemMapper.update(null, updateWrapper);
            }
        } else {
            // 异常 重新推送
            messageEntity = pushMsgWithResult2(mqManager, xRayMQConfig.getPushPACSScheduleChannelId(), xml);
            if ("0".equals(messageEntity.getEsbEntry().getRetInfo().getRetCode())) {
                XRayScheduleResponseESBEntry esbEntry =
                        JacksonUtil.readXmlValue(messageEntity.getMsg(), XRayScheduleResponseESBEntry.class);
                if (Objects.isNull(esbEntry) || Objects.isNull(esbEntry.getMsgInfo())) {
                    result = false;
                    return result;
                }
                /*
                 * 1. 判断发送是否成功
                 */
                XRayScheduleResponseMsg msg = esbEntry.getMsgInfo().getMsg();
                // 申请单号
                List<String> applyNoLists = msg.getDetails().stream()
                        .map(XRayResponseMsgDetail::getEquisitionNo)
                        .filter(StringUtils::isNoneBlank).collect(Collectors.toList());
                // 更新 预约的影像号和排队号
                List<ExamScheduleItem> examScheduleItems = examApplyMapper.getExamScheduleItemByApplyNos(applyNoLists);
                for (ExamScheduleItem item : examScheduleItems) {
                    item.setImageNo(msg.getImageNo());
                    item.setPacsSortNo(msg.getNo());
                    item.setPacsExamDept(msg.getTriageExamDept());
                    logger.info("重试!PACS返回影像号数据:{}", JacksonUtil.toJsonString(item));

                    UpdateWrapper<ExamScheduleItem> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.set("IMAGE_NO", msg.getImageNo());
                    updateWrapper.set("PACS_SORT_NO", msg.getNo());
                    updateWrapper.set("PACS_EXAM_DEPT", msg.getTriageExamDept());
                    updateWrapper.eq("SCHEDULED_ID", item.getScheduledId());
                    scheduleItemMapper.update(null, updateWrapper);
                }
            }
        }
        return result;
    }


    public MessageEntity pushMsgWithResult2(String queueName, String channelId, String msg) {
        checkMQTools();
        logger.info("pushMsgWithResult参数:{},{},{}", queueName, channelId, msg);
        try {
            MessageEntity messageEntity = ewellServiceTool.composePutAndGetMsg(queueName, channelId, 10000, msg);
            logger.info("pushMsgWithResult:返回结果:{}", JacksonUtil.toJsonString(messageEntity));
            return messageEntity;
        } catch (SDKException e) {
            logger.error("pushMsgWithResult:异常!" + e.getMessage(), e);
        }
        return null;
    }

    private void checkMQTools() {
        if (Objects.isNull(ewellServiceTool)) {
            ewellServiceTool = new EwellServiceTool();
        }
    }


    @Override
    public boolean cancelScheduleCSMsg(String applyNo, String mergeNo) {
        MQConfig.CSCancelRequest paramsConfig = mqConfig.getCsCancelRequest();
        final String cancelReqCode = "23", cancelSucCode = "23.1", cancelFailCode = "23.2";
        final String dateTimeFormatStr = "yyyy-MM-dd HH:mm:ss";
        if (!paramsConfig.isEnable()) {
            logger.info("cancelScheduleCSMsg:没有开启取消推送pacs。{},mergeNo:{}", applyNo, mergeNo);
            return true;
        }
        try {
            String scheduledDate = "";

            ExamScheduleItemVo scheduleItemVo = null;
            // 预约
            List<String> applyNos = Arrays.stream(mergeNo.split(","))
                    .map(x -> x.substring(0, x.indexOf("-")))
                    .collect(Collectors.toList());

            // 根据申请单号查询开单医生
            QueryWrapper<ExamApply> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("APPLY_NO", "REQ_PHYSICIAN_CODE");
            queryWrapper.eq("APPLY_NO", applyNo);
            List<ExamApply> examApplies = examApplyMapper.selectList(queryWrapper);
            String applyDrCode = "";
            if (!CollectionUtils.isEmpty(examApplies)) {
                applyDrCode = examApplies.get(0).getReqPhysicianCode();
            }

            SendMsg2 sendMsg = new SendMsg2();
            sendMsg.setOPER_STAFF_INDEX_NO(applyDrCode);
            sendMsg.setOPER_DATE(DateUtil.date2Str(new Date(), dateTimeFormatStr));
            sendMsg.setELECTR_REQUISITION_NO(applyNo);
            sendMsg.setSCHEDULE_QUEUE_NAME("admin");
            sendMsg.setREQUISITION_STATUS("取消预约");
            sendMsg.setREQUISITION_STATUS_CODE(cancelReqCode);
            sendMsg.setRESERVE_EXAM_DATE(scheduledDate);
            sendMsg.setNOTE("");

            List<ChangeExaminationStatusMsg> details = new ArrayList<>(applyNos.size());
            ChangeExaminationStatusMsg detail = null;
            for (String no : applyNos) {
                detail = new ChangeExaminationStatusMsg();
                detail.setREQUISITION_STATUS(sendMsg.getREQUISITION_STATUS());
                detail.setNOTE(sendMsg.getNOTE());
                detail.setOPER_DATE(sendMsg.getOPER_DATE());
                detail.setREQUISITION_STATUS_CODE(sendMsg.getREQUISITION_STATUS_CODE());
                detail.setOPER_STAFF_INDEX_NO(sendMsg.getOPER_STAFF_INDEX_NO());
                detail.setSCHEDULE_QUEUE_NAME(sendMsg.getSCHEDULE_QUEUE_NAME());
                detail.setRESERVE_EXAM_DATE(sendMsg.getRESERVE_EXAM_DATE());
                detail.setELECTR_REQUISITION_NO(no);
                details.add(detail);
            }

            SendMsgInfo msgInfo = new SendMsgInfo();
            sendMsg.setId(UUID.randomUUID().toString().replace("-", ""));
            sendMsg.setAction("insert");
            sendMsg.setLastUpdate(DateUtil.date2Str(new Date(), dateTimeFormatStr));
            sendMsg.setDetail(details);
            msgInfo.setMsg(sendMsg);

            MessageHeader header = new MessageHeader();
            header.setFid(paramsConfig.getFid());
            header.setMsgDate(DateUtil.date2Str(new Date(), dateTimeFormatStr));
            header.setOrderNo(paramsConfig.getOrderNo());
            header.setTargetSysCode(paramsConfig.getTargetSysCode());
            header.setSourceSysCode(paramsConfig.getSourceSystemCode());
            header.setReturnFlag(paramsConfig.getReturnFlag());
            header.setHospCode(paramsConfig.getHospCode());

            AccessControl accessControl = new AccessControl();
            accessControl.setFid(paramsConfig.getFid());
            accessControl.setOrderNo(paramsConfig.getOrderNo());
            accessControl.setSysFlag(paramsConfig.getSysFlag());
            accessControl.setUserName(paramsConfig.getUserName());
            accessControl.setPassword(paramsConfig.getPassword());

            SendESBEntry esbEntry = new SendESBEntry();
            esbEntry.setAccessControl(accessControl);
            esbEntry.setMessageHeader(header);
            esbEntry.setMsgInfo(msgInfo);

            String xmlString = JacksonUtil.toXmlString(esbEntry);
            logger.info(xmlString);

            MessageEntity result2 = pushMsgWithResult2(paramsConfig.getQueueName(), paramsConfig.getChannelId(), xmlString);
            // todo 判断是否取消成功
            String msg = result2.getMsg();
            return StringUtils.isNotEmpty(msg) && msg.contains("<REQUISITION_STATUS_CODE>" + cancelSucCode + "</REQUISITION_STATUS_CODE>");
        } catch (Exception e) {
            logger.error("cancelScheduleCSMsg:" + applyNo + "," + mergeNo, e);
            return false;
        }
    }


    public static void main(String[] args) {
        ChangeExaminationStatusMsg msg = new ChangeExaminationStatusMsg();
        msg.setNOTE("");
        msg.setOPER_DATE("1");
        msg.setREQUISITION_STATUS("1");
        msg.setRESERVE_EXAM_DATE("1");
        msg.setSCHEDULE_QUEUE_NAME("1");
        String xml = JacksonUtil.toXmlString(msg);
        System.out.println(xml);
    }
}
